{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "5c0122e65c053f38",
   "metadata": {},
   "source": [
    "# Hosting LangGraph agent with Amazon Bedrock models in Amazon Bedrock AgentCore Runtime\n",
    "\n",
    "## Overview\n",
    "\n",
    "In this tutorial we will learn how to host your existing agent, using Amazon Bedrock AgentCore Runtime. \n",
    "\n",
    "We will focus on a LangGraph with Amazon Bedrock model example. For Strands Agents with Amazon Bedrock model check [here](../01-strands-with-bedrock-model)\n",
    "and for a Strands Agents with an OpenAI model check [here](../03-strands-with-openai-model).\n",
    "\n",
    "### Tutorial Details\n",
    "\n",
    "| Information         | Details                                                                      |\n",
    "|:--------------------|:-----------------------------------------------------------------------------|\n",
    "| Tutorial type       | Conversational                                                               |\n",
    "| Agent type          | Single                                                                       |\n",
    "| Agentic Framework   | LangGraph                                                                    |\n",
    "| LLM model           | Anthropic Claude Sonnet 3                                                    |\n",
    "| Tutorial components | Hosting agent on AgentCore Runtime. Using LangGraph and Amazon Bedrock Model |\n",
    "| Tutorial vertical   | Cross-vertical                                                               |\n",
    "| Example complexity  | Easy                                                                         |\n",
    "| SDK used            | Amazon BedrockAgentCore Python SDK and boto3                                 |\n",
    "\n",
    "### Tutorial Architecture\n",
    "\n",
    "In this tutorial we will describe how to deploy an existing agent to AgentCore runtime. \n",
    "\n",
    "For demonstration purposes, we will  use a LangGraph agent using Amazon Bedrock models\n",
    "\n",
    "In our example we will use a very simple agent with two tools: `get_weather` and `get_time`. \n",
    "\n",
    "<div style=\"text-align:left\">\n",
    "    <img src=\"images/architecture_runtime.png\" width=\"50%\"/>\n",
    "</div>\n",
    "\n",
    "### Tutorial Key Features\n",
    "\n",
    "* Hosting Agents on Amazon Bedrock AgentCore Runtime\n",
    "* Using Amazon Bedrock models\n",
    "* Using LangGraph\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3a676f58ecf52b42",
   "metadata": {},
   "source": [
    "## Prerequisites\n",
    "\n",
    "To execute this tutorial you will need:\n",
    "* Python 3.10+\n",
    "* AWS credentials\n",
    "* Amazon Bedrock AgentCore SDK\n",
    "* LangGraph\n",
    "* Docker running"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "initial_id",
   "metadata": {
    "jupyter": {
     "is_executing": true
    }
   },
   "outputs": [],
   "source": [
    "#!uv add -r requirements.txt --active"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ca924a7a2731e26f",
   "metadata": {},
   "source": [
    "## Creating your agents and experimenting locally\n",
    "\n",
    "Before we deploy our agents to AgentCore Runtime, let's develop and run them locally for experimentation purposes.\n",
    "\n",
    "For production agentic applications we will need to decouple the agent creation process from the agent invocation one. With AgentCore Runtime, we will decorate the invocation part of our agent with the `@app.entrypoint` decorator and have it as the entry point for our runtime. Let's first look how each agent is developed during the experimentation phase.\n",
    "\n",
    "The architecture here will look as following:\n",
    "\n",
    "<div style=\"text-align:left\">\n",
    "    <img src=\"images/architecture_local.png\" width=\"60%\"/>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b7d386ab54e85e63",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%writefile langgraph_bedrock.py\n",
    "from langgraph.graph import StateGraph, MessagesState\n",
    "from langgraph.prebuilt import ToolNode, tools_condition\n",
    "from langchain_core.tools import tool\n",
    "from langchain_core.messages import HumanMessage, SystemMessage\n",
    "import argparse\n",
    "import json\n",
    "import operator\n",
    "import math\n",
    "\n",
    "# Create calculator tool\n",
    "@tool\n",
    "def calculator(expression: str) -> str:\n",
    "    \"\"\"\n",
    "    Calculate the result of a mathematical expression.\n",
    "    \n",
    "    Args:\n",
    "        expression: A mathematical expression as a string (e.g., \"2 + 3 * 4\", \"sqrt(16)\", \"sin(pi/2)\")\n",
    "    \n",
    "    Returns:\n",
    "        The result of the calculation as a string\n",
    "    \"\"\"\n",
    "    try:\n",
    "        # Define safe functions that can be used in expressions\n",
    "        safe_dict = {\n",
    "            \"__builtins__\": {},\n",
    "            \"abs\": abs, \"round\": round, \"min\": min, \"max\": max,\n",
    "            \"sum\": sum, \"pow\": pow,\n",
    "            # Math functions\n",
    "            \"sqrt\": math.sqrt, \"sin\": math.sin, \"cos\": math.cos, \"tan\": math.tan,\n",
    "            \"log\": math.log, \"log10\": math.log10, \"exp\": math.exp,\n",
    "            \"pi\": math.pi, \"e\": math.e,\n",
    "            \"ceil\": math.ceil, \"floor\": math.floor,\n",
    "            \"degrees\": math.degrees, \"radians\": math.radians,\n",
    "            # Basic operators (for explicit use)\n",
    "            \"add\": operator.add, \"sub\": operator.sub,\n",
    "            \"mul\": operator.mul, \"truediv\": operator.truediv,\n",
    "        }\n",
    "        \n",
    "        # Evaluate the expression safely\n",
    "        result = eval(expression, safe_dict)\n",
    "        return str(result)\n",
    "        \n",
    "    except ZeroDivisionError:\n",
    "        return \"Error: Division by zero\"\n",
    "    except ValueError as e:\n",
    "        return f\"Error: Invalid value - {str(e)}\"\n",
    "    except SyntaxError:\n",
    "        return \"Error: Invalid mathematical expression\"\n",
    "    except Exception as e:\n",
    "        return f\"Error: {str(e)}\"\n",
    "\n",
    "# Create a custom weather tool\n",
    "@tool\n",
    "def weather():\n",
    "    \"\"\"Get weather\"\"\"  # Dummy implementation\n",
    "    return \"sunny\"\n",
    "\n",
    "# Define the agent using manual LangGraph construction\n",
    "def create_agent():\n",
    "    \"\"\"Create and configure the LangGraph agent\"\"\"\n",
    "    from langchain_aws import ChatBedrock\n",
    "    \n",
    "    # Initialize your LLM (adjust model and parameters as needed)\n",
    "    llm = ChatBedrock(\n",
    "        model_id=\"anthropic.claude-3-sonnet-20240229-v1:0\",  # or your preferred model\n",
    "        model_kwargs={\"temperature\": 0.1}\n",
    "    )\n",
    "    \n",
    "    # Bind tools to the LLM\n",
    "    tools = [calculator, weather]\n",
    "    llm_with_tools = llm.bind_tools(tools)\n",
    "    \n",
    "    # System message\n",
    "    system_message = \"You're a helpful assistant. You can do simple math calculation, and tell the weather.\"\n",
    "    \n",
    "    # Define the chatbot node\n",
    "    def chatbot(state: MessagesState):\n",
    "        # Add system message if not already present\n",
    "        messages = state[\"messages\"]\n",
    "        if not messages or not isinstance(messages[0], SystemMessage):\n",
    "            messages = [SystemMessage(content=system_message)] + messages\n",
    "        \n",
    "        response = llm_with_tools.invoke(messages)\n",
    "        return {\"messages\": [response]}\n",
    "    \n",
    "    # Create the graph\n",
    "    graph_builder = StateGraph(MessagesState)\n",
    "    \n",
    "    # Add nodes\n",
    "    graph_builder.add_node(\"chatbot\", chatbot)\n",
    "    graph_builder.add_node(\"tools\", ToolNode(tools))\n",
    "    \n",
    "    # Add edges\n",
    "    graph_builder.add_conditional_edges(\n",
    "        \"chatbot\",\n",
    "        tools_condition,\n",
    "    )\n",
    "    graph_builder.add_edge(\"tools\", \"chatbot\")\n",
    "    \n",
    "    # Set entry point\n",
    "    graph_builder.set_entry_point(\"chatbot\")\n",
    "    \n",
    "    # Compile the graph\n",
    "    return graph_builder.compile()\n",
    "\n",
    "# Initialize the agent\n",
    "agent = create_agent()\n",
    "\n",
    "def langgraph_bedrock(payload):\n",
    "    \"\"\"\n",
    "    Invoke the agent with a payload\n",
    "    \"\"\"\n",
    "    user_input = payload.get(\"prompt\")\n",
    "    \n",
    "    # Create the input in the format expected by LangGraph\n",
    "    response = agent.invoke({\"messages\": [HumanMessage(content=user_input)]})\n",
    "    \n",
    "    # Extract the final message content\n",
    "    return response[\"messages\"][-1].content\n",
    "\n",
    "if __name__ == \"__main__\":\n",
    "    parser = argparse.ArgumentParser()\n",
    "    parser.add_argument(\"payload\", type=str)\n",
    "    args = parser.parse_args()\n",
    "    response = langgraph_bedrock(json.loads(args.payload))\n",
    "    print(response)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "68499675-db8d-47c6-8c0c-5d66dcb06229",
   "metadata": {},
   "source": [
    "#### Invoking local agent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1226d59e6b56c96",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-29T21:52:06.461281Z",
     "start_time": "2025-06-29T21:52:06.456854Z"
    }
   },
   "outputs": [],
   "source": [
    "!python langgraph_bedrock.py '{\"prompt\": \"What is the weather now?\"}'"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "932110e6-fca6-47b6-b7c5-c4714a866a80",
   "metadata": {},
   "source": [
    "## Preparing your agent for deployment on AgentCore Runtime\n",
    "\n",
    "Let's now deploy our agents to AgentCore Runtime. To do so we need to:\n",
    "* Import the Runtime App with `from bedrock_agentcore.runtime import BedrockAgentCoreApp`\n",
    "* Initialize the App in our code with `app = BedrockAgentCoreApp()`\n",
    "* Decorate the invocation function with the `@app.entrypoint` decorator\n",
    "* Let AgentCoreRuntime control the running of the agent with `app.run()`\n",
    "\n",
    "### LangGraph with Amazon Bedrock model\n",
    "Let's start with our LangGraph using Amazon Bedrock model. Other examples with different frameworks and models are available in the parent directories"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3b845b32-a03e-45c2-a2f0-2afba8069f47",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%writefile langgraph_bedrock.py\n",
    "from langgraph.graph import StateGraph, MessagesState\n",
    "from langgraph.prebuilt import ToolNode, tools_condition\n",
    "from langchain_core.tools import tool\n",
    "from langchain_core.messages import HumanMessage, SystemMessage\n",
    "from bedrock_agentcore.runtime import BedrockAgentCoreApp\n",
    "import argparse\n",
    "import json\n",
    "import operator\n",
    "import math\n",
    "\n",
    "app = BedrockAgentCoreApp()\n",
    "\n",
    "# Create calculator tool\n",
    "@tool\n",
    "def calculator(expression: str) -> str:\n",
    "    \"\"\"\n",
    "    Calculate the result of a mathematical expression.\n",
    "    \n",
    "    Args:\n",
    "        expression: A mathematical expression as a string (e.g., \"2 + 3 * 4\", \"sqrt(16)\", \"sin(pi/2)\")\n",
    "    \n",
    "    Returns:\n",
    "        The result of the calculation as a string\n",
    "    \"\"\"\n",
    "    try:\n",
    "        # Define safe functions that can be used in expressions\n",
    "        safe_dict = {\n",
    "            \"__builtins__\": {},\n",
    "            \"abs\": abs, \"round\": round, \"min\": min, \"max\": max,\n",
    "            \"sum\": sum, \"pow\": pow,\n",
    "            # Math functions\n",
    "            \"sqrt\": math.sqrt, \"sin\": math.sin, \"cos\": math.cos, \"tan\": math.tan,\n",
    "            \"log\": math.log, \"log10\": math.log10, \"exp\": math.exp,\n",
    "            \"pi\": math.pi, \"e\": math.e,\n",
    "            \"ceil\": math.ceil, \"floor\": math.floor,\n",
    "            \"degrees\": math.degrees, \"radians\": math.radians,\n",
    "            # Basic operators (for explicit use)\n",
    "            \"add\": operator.add, \"sub\": operator.sub,\n",
    "            \"mul\": operator.mul, \"truediv\": operator.truediv,\n",
    "        }\n",
    "        \n",
    "        # Evaluate the expression safely\n",
    "        result = eval(expression, safe_dict)\n",
    "        return str(result)\n",
    "        \n",
    "    except ZeroDivisionError:\n",
    "        return \"Error: Division by zero\"\n",
    "    except ValueError as e:\n",
    "        return f\"Error: Invalid value - {str(e)}\"\n",
    "    except SyntaxError:\n",
    "        return \"Error: Invalid mathematical expression\"\n",
    "    except Exception as e:\n",
    "        return f\"Error: {str(e)}\"\n",
    "\n",
    "# Create a custom weather tool\n",
    "@tool\n",
    "def weather():\n",
    "    \"\"\"Get weather\"\"\"  # Dummy implementation\n",
    "    return \"sunny\"\n",
    "\n",
    "# Define the agent using manual LangGraph construction\n",
    "def create_agent():\n",
    "    \"\"\"Create and configure the LangGraph agent\"\"\"\n",
    "    from langchain_aws import ChatBedrock\n",
    "    \n",
    "    # Initialize your LLM (adjust model and parameters as needed)\n",
    "    llm = ChatBedrock(\n",
    "        model_id=\"anthropic.claude-3-sonnet-20240229-v1:0\",  # or your preferred model\n",
    "        model_kwargs={\"temperature\": 0.1}\n",
    "    )\n",
    "    \n",
    "    # Bind tools to the LLM\n",
    "    tools = [calculator, weather]\n",
    "    llm_with_tools = llm.bind_tools(tools)\n",
    "    \n",
    "    # System message\n",
    "    system_message = \"You're a helpful assistant. You can do simple math calculation, and tell the weather.\"\n",
    "    \n",
    "    # Define the chatbot node\n",
    "    def chatbot(state: MessagesState):\n",
    "        # Add system message if not already present\n",
    "        messages = state[\"messages\"]\n",
    "        if not messages or not isinstance(messages[0], SystemMessage):\n",
    "            messages = [SystemMessage(content=system_message)] + messages\n",
    "        \n",
    "        response = llm_with_tools.invoke(messages)\n",
    "        return {\"messages\": [response]}\n",
    "    \n",
    "    # Create the graph\n",
    "    graph_builder = StateGraph(MessagesState)\n",
    "    \n",
    "    # Add nodes\n",
    "    graph_builder.add_node(\"chatbot\", chatbot)\n",
    "    graph_builder.add_node(\"tools\", ToolNode(tools))\n",
    "    \n",
    "    # Add edges\n",
    "    graph_builder.add_conditional_edges(\n",
    "        \"chatbot\",\n",
    "        tools_condition,\n",
    "    )\n",
    "    graph_builder.add_edge(\"tools\", \"chatbot\")\n",
    "    \n",
    "    # Set entry point\n",
    "    graph_builder.set_entry_point(\"chatbot\")\n",
    "    \n",
    "    # Compile the graph\n",
    "    return graph_builder.compile()\n",
    "\n",
    "# Initialize the agent\n",
    "agent = create_agent()\n",
    "\n",
    "@app.entrypoint\n",
    "def langgraph_bedrock(payload):\n",
    "    \"\"\"\n",
    "    Invoke the agent with a payload\n",
    "    \"\"\"\n",
    "    user_input = payload.get(\"prompt\")\n",
    "    \n",
    "    # Create the input in the format expected by LangGraph\n",
    "    response = agent.invoke({\"messages\": [HumanMessage(content=user_input)]})\n",
    "    \n",
    "    # Extract the final message content\n",
    "    return response[\"messages\"][-1].content\n",
    "\n",
    "if __name__ == \"__main__\":\n",
    "    app.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c64db7b5-0f1b-475f-9bf2-467b4449d46a",
   "metadata": {},
   "source": [
    "## What happens behind the scenes?\n",
    "\n",
    "When you use `BedrockAgentCoreApp`, it automatically:\n",
    "\n",
    "* Creates an HTTP server that listens on the port 8080\n",
    "* Implements the required `/invocations` endpoint for processing the agent's requirements\n",
    "* Implements the `/ping` endpoint for health checks (very important for asynchronous agents)\n",
    "* Handles proper content types and response formats\n",
    "* Manages error handling according to the AWS standards"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6820ca8f-a8a8-4f34-b4ef-b6dad3776261",
   "metadata": {},
   "source": [
    "## Deploying the agent to AgentCore Runtime\n",
    "\n",
    "The `CreateAgentRuntime` operation supports comprehensive configuration options, letting you specify container images, environment variables and encryption settings. You can also configure protocol settings (HTTP, MCP) and authorization mechanisms to control how your clients communicate with the agent. \n",
    "\n",
    "**Note:** Operations best practice is to package code as container and push to ECR using CI/CD pipelines and IaC\n",
    "\n",
    "In this tutorial can will the Amazon Bedrock AgentCode Python SDK to easily package your artifacts and deploy them to AgentCore runtime."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d0861401-a111-4ade-9e02-50f52fdfa9b1",
   "metadata": {},
   "source": [
    "### Creating runtime role\n",
    "\n",
    "Before starting, let's create an IAM role for our AgentCore Runtime. We will do so using the utils function pre-developed for you."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "54dd2fdf-985c-4a70-8b87-071783a209de",
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "import os\n",
    "\n",
    "# Get the current notebook's directory\n",
    "current_dir = os.path.dirname(os.path.abspath('__file__' if '__file__' in globals() else '.'))\n",
    "\n",
    "utils_dir = os.path.join(current_dir, '..')\n",
    "utils_dir = os.path.join(utils_dir, '..')\n",
    "utils_dir = os.path.abspath(utils_dir)\n",
    "\n",
    "# Add to sys.path\n",
    "sys.path.insert(0, utils_dir)\n",
    "print(\"sys.path[0]:\", sys.path[0])\n",
    "\n",
    "from utils import create_agentcore_role\n",
    "\n",
    "agent_name=\"langgraph_bedrock\"\n",
    "agentcore_iam_role = create_agentcore_role(agent_name=agent_name)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8855aceb-b79f-4aaa-b16f-8577c059816a",
   "metadata": {},
   "source": [
    "### Configure AgentCore Runtime deployment\n",
    "\n",
    "Next we will use our starter toolkit to configure the AgentCore Runtime deployment with an entrypoint, the execution role we just created and a requirements file. We will also configure the starter kit to auto create the Amazon ECR repository on launch.\n",
    "\n",
    "During the configure step, your docker file will be generated based on your application code\n",
    "\n",
    "<div style=\"text-align:left\">\n",
    "    <img src=\"images/configure.png\" width=\"40%\"/>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2e79eba2-ca59-463f-9ebf-56e362d7ae66",
   "metadata": {},
   "outputs": [],
   "source": [
    "from bedrock_agentcore_starter_toolkit import Runtime\n",
    "from boto3.session import Session\n",
    "boto_session = Session()\n",
    "region = boto_session.region_name\n",
    "region\n",
    "\n",
    "agentcore_runtime = Runtime()\n",
    "\n",
    "response = agentcore_runtime.configure(\n",
    "    entrypoint=\"langgraph_bedrock.py\",\n",
    "    execution_role=agentcore_iam_role['Role']['Arn'],\n",
    "    auto_create_ecr=True,\n",
    "    requirements_file=\"requirements.txt\",\n",
    "    region=region\n",
    ")\n",
    "response"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9e1b84cc-798e-472c-ac0b-2c315f4b704d",
   "metadata": {},
   "source": [
    "### Launching agent to AgentCore Runtime\n",
    "\n",
    "Now that we've got a docker file, let's launch the agent to the AgentCore Runtime. This will create the Amazon ECR repository and the AgentCore Runtime\n",
    "\n",
    "<div style=\"text-align:left\">\n",
    "    <img src=\"images/launch.png\" width=\"75%\"/>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "17a32ab8-7701-4900-8055-e24364bdf35c",
   "metadata": {},
   "outputs": [],
   "source": [
    "launch_result = agentcore_runtime.launch()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a0ae9c09-09db-4a76-871a-92eacd96b9c3",
   "metadata": {},
   "source": [
    "### Checking for the AgentCore Runtime Status\n",
    "Now that we've deployed the AgentCore Runtime, let's check for it's deployment status"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "afa6ac09-9adb-4846-9fc1-4d12aeb74853",
   "metadata": {},
   "outputs": [],
   "source": [
    "status_response = agentcore_runtime.status()\n",
    "status = status_response.endpoint['status']\n",
    "end_status = ['READY', 'CREATE_FAILED', 'DELETE_FAILED', 'UPDATE_FAILED']\n",
    "while status not in end_status:\n",
    "    time.sleep(10)\n",
    "    status_response = agentcore_runtime.status()\n",
    "    status = status_response.endpoint['status']\n",
    "    print(status)\n",
    "status"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b7f89c56-918a-4cab-beaa-c7ac43a2ba29",
   "metadata": {},
   "source": [
    "### Invoking AgentCore Runtime\n",
    "\n",
    "Finally, we can invoke our AgentCore Runtime with a payload\n",
    "\n",
    "<div style=\"text-align:left\">\n",
    "    <img src=\"images/invoke.png\" width=75%\"/>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3d909e42-e1a0-407f-84c2-3d16cc889cd3",
   "metadata": {},
   "outputs": [],
   "source": [
    "invoke_response = agentcore_runtime.invoke({\"prompt\": \"How much is 2+2?\"})\n",
    "invoke_response"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fefa09f2-d25a-483f-aedb-11690bb8923a",
   "metadata": {},
   "source": [
    "### Processing invocation results\n",
    "\n",
    "We can now process our invocation results to include it in an application"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "11249103-cfb3-47b5-970d-981a977a225a",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "from IPython.display import Markdown, display\n",
    "import json\n",
    "response_text = json.loads(invoke_response['response'][0].decode(\"utf-8\"))\n",
    "display(Markdown(response_text))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2c1d2bce-be41-478c-8bed-b4037c385795",
   "metadata": {},
   "source": [
    "### Invoking AgentCore Runtime with boto3\n",
    "\n",
    "Now that your AgentCore Runtime was created you can invoke it with any AWS SDK. For instance, you can use the boto3 `invoke_agent_runtime` method for it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7f84e68d-6c04-41b9-bf5b-60edc3fa0985",
   "metadata": {},
   "outputs": [],
   "source": [
    "import boto3\n",
    "agent_arn = launch_result.agent_arn\n",
    "agentcore_client = boto3.client(\n",
    "    'bedrock-agentcore',\n",
    "    region_name=region\n",
    ")\n",
    "\n",
    "boto3_response = agentcore_client.invoke_agent_runtime(\n",
    "    agentRuntimeArn=agent_arn,\n",
    "    qualifier=\"DEFAULT\",\n",
    "    payload=json.dumps({\"prompt\": \"What is the weather now?\"})\n",
    ")\n",
    "if \"text/event-stream\" in boto3_response.get(\"contentType\", \"\"):\n",
    "    content = []\n",
    "    for line in boto3_response[\"response\"].iter_lines(chunk_size=1):\n",
    "        if line:\n",
    "            line = line.decode(\"utf-8\")\n",
    "            if line.startswith(\"data: \"):\n",
    "                line = line[6:]\n",
    "                logger.info(line)\n",
    "                content.append(line)\n",
    "    display(Markdown(\"\\n\".join(content)))\n",
    "else:\n",
    "    try:\n",
    "        events = []\n",
    "        for event in boto3_response.get(\"response\", []):\n",
    "            events.append(event)\n",
    "    except Exception as e:\n",
    "        events = [f\"Error reading EventStream: {e}\"]\n",
    "    display(Markdown(json.loads(events[0].decode(\"utf-8\"))))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7d3fdfe404469632",
   "metadata": {},
   "source": [
    "## Cleanup (Optional)\n",
    "\n",
    "Let's now clean up the AgentCore Runtime created"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "08f86824-c775-4ad4-aaee-f18e8cf390b9",
   "metadata": {},
   "outputs": [],
   "source": [
    "launch_result.ecr_uri, launch_result.agent_id, launch_result.ecr_uri.split('/')[1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "76a6cf1416830a54",
   "metadata": {},
   "outputs": [],
   "source": [
    "agentcore_control_client = boto3.client(\n",
    "    'bedrock-agentcore-control',\n",
    "    region_name=region\n",
    ")\n",
    "ecr_client = boto3.client(\n",
    "    'ecr',\n",
    "    region_name=region\n",
    "    \n",
    ")\n",
    "\n",
    "iam_client = boto3.client('iam')\n",
    "\n",
    "runtime_delete_response = agentcore_control_client.delete_agent_runtime(\n",
    "    agentRuntimeId=launch_result.agent_id\n",
    ")\n",
    "\n",
    "response = ecr_client.delete_repository(\n",
    "    repositoryName=launch_result.ecr_uri.split('/')[1],\n",
    "    force=True\n",
    ")\n",
    "policies = iam_client.list_role_policies(\n",
    "    RoleName=agentcore_iam_role['Role']['RoleName'],\n",
    "    MaxItems=100\n",
    ")\n",
    "\n",
    "for policy_name in policies['PolicyNames']:\n",
    "    iam_client.delete_role_policy(\n",
    "        RoleName=agentcore_iam_role['Role']['RoleName'],\n",
    "        PolicyName=policy_name\n",
    "    )\n",
    "iam_response = iam_client.delete_role(\n",
    "    RoleName=agentcore_iam_role['Role']['RoleName']\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b118ad38-feeb-4d1d-9d57-e5c845becc56",
   "metadata": {},
   "source": [
    "# Congratulations!"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
